package ac.github.oa.listener

import ac.github.oa.OriginAttribute
import ac.github.oa.api.Debug
import ac.github.oa.api.OriginAttributeAPI
import ac.github.oa.api.OriginAttributeAPI.asyncHeal
import ac.github.oa.api.event.entity.EntityDamageEvent
import ac.github.oa.api.event.entity.EntityDeathEvent
import ac.github.oa.api.event.entity.ProxyDamageEvent
import ac.github.oa.api.event.render.AttributeRenderStringEvent
import ac.github.oa.internal.base.enums.PriorityEnum
import ac.github.oa.util.ArrayUtils
import io.lumine.mythic.bukkit.events.MythicMobDeathEvent
import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMobSpawnEvent
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import org.bukkit.event.entity.*
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.player.PlayerDropItemEvent
import org.bukkit.event.player.PlayerItemHeldEvent
import org.bukkit.event.player.PlayerJoinEvent
import taboolib.common.platform.event.EventPriority
import taboolib.common.platform.event.OptionalEvent
import taboolib.common.platform.event.SubscribeEvent
import taboolib.platform.util.setMeta

object OnListener {

    private val damageCauses: List<String>
        get() = OriginAttribute.config.getStringList("options.damage-cause")

    private val joinHeal: Boolean
        get() = OriginAttribute.config.getBoolean("options.join-heal")


    @SubscribeEvent
    fun e(e: ProxyDamageEvent) {

        val context = e.createDamageContext()

        if (EntityDamageEvent(context, PriorityEnum.PRE).call()) {
            OriginAttributeAPI.callDamage(context)

            // POST CALL 战斗后不允许取消事件
            if (EntityDamageEvent(context, PriorityEnum.POST).call()) {
                e.damage = context.totalDamage.coerceAtLeast(0.0)
                Debug.log("DamageByEntity info:")
                context.getDamageSources().forEachIndexed { index, source ->
                    Debug.log("$index.${source.any} = ${source.value}")
                }

            }
        } else {
            e.isCancelled = true
        }

    }


    @SubscribeEvent(ignoreCancelled = true, priority = EventPriority.MONITOR)
    fun e(e: EntityDamageByEntityEvent) {
        if (e.cause.name in damageCauses && e.entity::class.java.simpleName != "PlayerNPC") {
            val proxyEvent = ProxyDamageEvent(e)
            if (proxyEvent.call()) {
                e.damage = proxyEvent.damage.coerceAtLeast(0.0)
            } else {
                e.isCancelled = true
            }
        }

    }

    @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true)
    fun e(event: EntityShootBowEvent) {
        val entity = event.projectile
        entity.setMeta("attributeData", OriginAttributeAPI.getAttributeData(event.entity))
        entity.setMeta("force", event.force)
        // 附着弓实体
        if (event.bow != null) {
            entity.setMeta("bow", event.bow!!)
        }
    }

    @SubscribeEvent
    fun e(event: ItemSpawnEvent) {
        if (event.isCancelled || event.entity.isCustomNameVisible) return
        val item = event.entity
        val itemStack = item.itemStack
        if (!event.isCancelled && itemStack.hasItemMeta() && itemStack.itemMeta!!.hasDisplayName()) {
            item.isCustomNameVisible = true
            if (itemStack.amount > 1) {
                item.customName = itemStack.itemMeta!!.displayName + " §b*" + itemStack.amount
            } else {
                item.customName = itemStack.itemMeta!!.displayName
            }
        }
    }

    @SubscribeEvent
    fun e(event: ItemMergeEvent) {
        if (event.isCancelled) return
        val item = event.target
        val oldItem = event.entity
        if (item.isCustomNameVisible) {
            item.customName =
                item.itemStack.itemMeta!!.displayName + " §b*" + (item.itemStack.amount + oldItem.itemStack.amount)
        }
    }

    @SubscribeEvent
    fun e(e: AttributeRenderStringEvent) {

        e.list.forEachIndexed { index, s ->
            var string = s
            val matchResult = OriginAttribute.numberRegex.find(s)
            matchResult?.apply {
                this.groupValues.forEach {
                    string =
                        s.replace(it, it.replace(OriginAttribute.config.getString("options.operator-add", "+")!!, "+"))
                    string =
                        s.replace(it, it.replace(OriginAttribute.config.getString("options.operator-take", "-")!!, "+"))
                }
            }
            e.list[index] = string
        }
    }


    @SubscribeEvent
    fun e(e: PlayerJoinEvent) {
        if (joinHeal) {
            asyncHeal(e.player)
        } else {
            asyncUpdate(e.player)
        }
    }

    @SubscribeEvent
    fun e(e: EntityPickupItemEvent) {
        asyncUpdate(e.entity)
    }

    @SubscribeEvent
    fun e(e: PlayerDropItemEvent) {
        asyncUpdate(e.player)
    }

    @SubscribeEvent
    fun e(e: PlayerItemHeldEvent) {
        asyncUpdate(e.player)
    }

    @SubscribeEvent
    fun e(e: InventoryCloseEvent) {
        asyncUpdate(e.player)
    }

    @SubscribeEvent(bind = "io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMobSpawnEvent")
    fun handleMythicSpawn(ope: OptionalEvent) {
        val event = ope.get<MythicMobSpawnEvent>()
        val entity: Entity = event.entity

        if (entity is LivingEntity) {
            asyncMythicMob(
                entity,
                ArrayUtils.read(entity, event.mobType.config.getStringList("Attributes"), event.mobLevel),
                15
            )
        }
    }

    @SubscribeEvent(bind = "io.lumine.mythic.bukkit.events.MythicMobSpawnEvent")
    fun handleMythic5Spawn(ope: OptionalEvent) {
        val event = ope.get<io.lumine.mythic.bukkit.events.MythicMobSpawnEvent>()
        val entity: Entity = event.entity

        if (entity is LivingEntity) {
            asyncMythicMob(
                entity,
                ArrayUtils.read(entity, event.mobType.config.getStringList("Attributes"), event.mobLevel),
                15
            )
        }
    }

    fun asyncMythicMob(entity: LivingEntity, attributes: List<String>, delay: Long) {
        OriginAttributeAPI.async(delay = delay) {
            OriginAttributeAPI.loadEntityEquipment(entity).merge(
                OriginAttributeAPI.loadList(attributes)
            )
            OriginAttributeAPI.callUpdate(entity)
        }
    }

    @SubscribeEvent(bind = "io.lumine.xikage.mythicmobs.api.bukkit.events.EntityDeathEvent")
    fun handleMythicDeath(ope: OptionalEvent) {
        val event = ope.get<EntityDeathEvent>()
        val entity: Entity = event.entity
        if (entity is LivingEntity) {
            OriginAttributeAPI.remove(entity.uniqueId)
        }
    }

    @SubscribeEvent(bind = "io.lumine.mythic.bukkit.events.MythicMobDeathEvent")
    fun handleMythic5Death(ope: OptionalEvent) {
        val event = ope.get<MythicMobDeathEvent>()
        val entity: Entity = event.entity
        if (entity is LivingEntity) {
            OriginAttributeAPI.remove(entity.uniqueId)
        }
    }

    fun asyncUpdate(entity: LivingEntity, delay: Long = 0) {
        OriginAttributeAPI.async(delay = delay) {
            OriginAttributeAPI.loadEntityEquipment(entity)
            OriginAttributeAPI.callUpdate(entity)
        }
    }

}
